using System.Reflection;
using System.Text;
using KL.Core.Common.Utils;
using KL.Standard.Domain.Repositories;
using KL.Standard.Model.Attribute;
using KL.Standard.Model.Infrastructure;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Caching.Memory;

namespace EagCentralPlatform.Net8.Filter;

/// <summary>
/// 日志过滤器
/// </summary>
public class LogFilterAttribute : ActionFilterAttribute
{
    private readonly IOpeLogRepository _opeLogRepository;
    private readonly IBaseDataRepository _baseDataRepository;
    private readonly ILogger<LogFilterAttribute> _log;

    public static IMemoryCache _cache = new MemoryCache(new MemoryCacheOptions());

    public LogFilterAttribute(IOpeLogRepository repository, ILogger<LogFilterAttribute> log,
        IBaseDataRepository repository2)
    {
        this._opeLogRepository = repository;
        this._baseDataRepository = repository2;
        this._log = log;
    }

    public override void OnActionExecuting(ActionExecutingContext actionContext)
    {


    }

    /// <summary>
    /// 在方法执行完之后记录日志
    /// 只有新增修改删除才会记录数据表
    /// </summary>
    /// <param name="actionExecutedContext"></param>
    public override async void OnActionExecuted(ActionExecutedContext actionExecutedContext)
    {
        if (actionExecutedContext.Exception == null) //无异常时才能执行
        {
            string controllerName = actionExecutedContext.RouteData.Values["Controller"].ToString();
            string actionName = actionExecutedContext.RouteData.Values["Action"]?.ToString() ?? "";
            string path = actionExecutedContext.HttpContext.Request.Path;
            //actionExecutedContext.HttpContext.Request.

            #region log文件写入访问日志

            var attributes =
                ((Microsoft.AspNetCore.Mvc.Controllers.ControllerActionDescriptor)actionExecutedContext
                    .ActionDescriptor).MethodInfo.GetCustomAttributes();
            bool isAnonymous = attributes.Any(a => a is AllowAnonymousAttribute); //无授权拦截
            var logConfig = attributes.FirstOrDefault(a => a is LogConfigAttribute) as LogConfigAttribute; //有无日志配置
            bool isIgnoreRequestTxt = (logConfig?.IsIgnoreRequestTxt) ?? false;
            CurUserInfo curUserInfo = null;
            //string loginID = "";
            //GetRequestValues(actionExecutedContext);
            string requestStr = string.Empty;
            if (!isIgnoreRequestTxt)
                requestStr = await GetReuestBody_New(actionExecutedContext);
            //string requestStr = string.Empty;
            if (!isAnonymous)
            {
                curUserInfo = ClaimUtils.GetInfo4Claims<CurUserInfo>(actionExecutedContext.HttpContext.User);
                if (string.IsNullOrEmpty(curUserInfo.loginID))
                {
                    _log.LogError(" loginID 为空，获取不到用户信息");
                    throw new Exception("获取不到用户信息");
                }
            }

            _log.LogInformation("invoke url:{0},user:{1},param:{2}", path, curUserInfo?.loginID, requestStr);

            #endregion

            #region 记录操作日志

            List<string> list = new List<string>();
            //调整记录日志逻辑，对于特定controller 和action 才不做记录
            //
            if (!_cache.TryGetValue("no_filter_controller_and_action", out IEnumerable<string> array))
            {
                array = _baseDataRepository.GetMethods4Filter();
                _cache.Set("no_filter_controller_and_action", array, new TimeSpan(0, 5, 0));
            }

            var controllerAndAction = $"{controllerName.ToLower()}#{actionName.ToLower()}";
            if (!(array.Any(i => controllerAndAction.IndexOf(i) > -1))) //执行记录更新
            {
                if (actionExecutedContext.HttpContext.Response.StatusCode == 200)
                {
                    var br = (actionExecutedContext.Result as ObjectResult)?.Value as BaseResult<string>;
                    //var res.Value as BaseResult<string>;
                    if (br != null && br.success)
                    {
                        _opeLogRepository.writeLog(curUserInfo?.loginID??"", controllerName, actionName, path,
                            requestStr, "");
                    }
                }
            }

            #endregion
        }

        base.OnActionExecuted(actionExecutedContext);
    }


    private async Task<string> GetReuestBody_New(ActionExecutedContext context)
    {
        HttpRequest request = context.HttpContext.Request;
        string content = string.Empty;
        try
        {
            request.EnableBuffering();
            request.Body.Position = 0;
            StreamReader sr = new StreamReader(request.Body);
            content = await sr.ReadToEndAsync();
            request.Body.Position = 0;

            return content;
        }
        catch (Exception ex)
        {
            _log.LogError("获取 request body 异常：{0}", ex.StackTrace);
            return await Task.FromResult(content);
        }


    }



    private string GetReuestBody(ActionExecutedContext context)
    {
        HttpRequest request = context.HttpContext.Request;
        string content = string.Empty;
        try
        {
            request.EnableBuffering();
            using (Stream stream = request.Body)
            {
                byte[] buffer = new byte[request.ContentLength.Value];
                stream.Read(buffer, 0, buffer.Length);
                content = Encoding.UTF8.GetString(buffer);
                request.Body.Position = 0;

            }

            return content;
        }
        catch (Exception ex)
        {
            _log.LogError("获取 request body 异常：{0}", ex.StackTrace);
            return content;
        }


    }

    private string GetRequestValues(ActionExecutedContext context)
    {
        HttpRequest request = context.HttpContext.Request;
        if (request.ContentLength != null && request.ContentLength.Value > 0)
        {
            request.EnableBuffering();
            Stream stream = request.Body;
            byte[] buffer = new byte[request.ContentLength.Value];
            stream.Read(buffer, 0, buffer.Length);
            string querystring = Encoding.UTF8.GetString(buffer);
            request.Body.Position = 0;
            return querystring;
        }
        else
        {
            return "";
        }

    }
}